#include "QMPlay2MacExtensions.hpp"

#include <QAbstractNativeEventFilter>
#include <QGuiApplication>
#include <QWindow>

#include <IOKit/hidsystem/ev_keymap.h>
#include <AppKit/NSApplication.h>
#include <AppKit/NSScreen.h>
#include <AppKit/NSEvent.h>

class MediaKeysFilter : public QAbstractNativeEventFilter
{
public:
	MediaKeysFilter(const QMPlay2MacExtensions::MediaKeysCallback &cb) :
		m_mediaKeysCallback(cb)
	{}

private:
	bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override final
	{
		Q_UNUSED(result)
		if (eventType == "mac_generic_NSEvent")
		{
			NSEvent *event = static_cast<NSEvent *>(message);
#if defined(MAC_OS_X_VERSION_10_12) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
			if ([event type] == NSEventTypeSystemDefined)
#else
			if ([event type] == NSSystemDefined)
#endif
			{
				const int  keyCode   = ([event data1] & 0xFFFF0000) >> 16;
				const int  keyFlags  = ([event data1] & 0x0000FFFF);
				const int  keyState  = (((keyFlags & 0xFF00) >> 8) == 0xA);
				const bool keyRepeat = (keyFlags & 0x1);
				Q_UNUSED(keyRepeat)

				if (keyState == 1)
				{
					switch (keyCode)
					{
						case NX_KEYTYPE_PLAY:
							m_mediaKeysCallback("toggle");
							return true;
						case NX_KEYTYPE_NEXT:
						case NX_KEYTYPE_FAST:
							m_mediaKeysCallback("next");
							return true;
						case NX_KEYTYPE_PREVIOUS:
						case NX_KEYTYPE_REWIND:
							m_mediaKeysCallback("prev");
							return true;
					}
				}
			}
		}
		return false;
	}

	QMPlay2MacExtensions::MediaKeysCallback m_mediaKeysCallback;
} static *g_mediaKeysFilter;

/**/

void QMPlay2MacExtensions::setApplicationVisible(bool visible)
{
	static NSApplication *app = [NSApplication sharedApplication];
	if (visible)
		[app unhide:nil];
	else
		[app hide:nil];
}

void QMPlay2MacExtensions::registerMacOSMediaKeys(const MediaKeysCallback &cb)
{
	if (!g_mediaKeysFilter)
	{
		g_mediaKeysFilter = new MediaKeysFilter(cb);
		QCoreApplication::instance()->installNativeEventFilter(g_mediaKeysFilter);
	}
}
void QMPlay2MacExtensions::unregisterMacOSMediaKeys()
{
	if (g_mediaKeysFilter)
	{
		QCoreApplication::instance()->removeNativeEventFilter(g_mediaKeysFilter);
		delete g_mediaKeysFilter;
		g_mediaKeysFilter = nullptr;
	}
}

void QMPlay2MacExtensions::showSystemUi(QWindow *mainWindow, bool visible)
{
#if defined(MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)
	if (mainWindow && mainWindow->screen() != QGuiApplication::primaryScreen() && ![NSScreen screensHaveSeparateSpaces])
		return;
#endif
	unsigned long flags;
	if (visible)
		flags = NSApplicationPresentationDefault;
	else
		flags = NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar;
	[NSApp setPresentationOptions:flags];
}
